﻿using System;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using QAToolsAddin.GenericDialogs;
using QAToolsAddin.GenericDialogs.Fields;
using Excel = Microsoft.Office.Interop.Excel;

namespace QAToolsAddin.UI {
    class Text {
        private readonly Excel.Application _excelapp;
        private Excel.Range _range;
        private CultureInfo _culture;

        public Text(Excel.Application application, CultureInfo culture) {
            try {
                _excelapp = application;
                _culture = culture;
                _range = application.ActiveWindow.RangeSelection;
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }

        public void TrimTextSpace() {
            try {
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string)
                        value = ((string)value).Trim();
                });
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }

        public void ToLower() {
            try {
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string)
                        value = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToLower((string)value);
                });
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }

        public void ToUpper() {
            try {
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string)
                        value = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToUpper((string)value);
                });
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }

        public void ToPropper() {
            try {
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string)
                        value = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(((string)value).ToLower());
                });
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }

        public void Reverse() {
            try {
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string) {
                        var res = string.Empty;
                        foreach (char car in (string)value)
                            res = car + res;
                        value = res;
                    }
                });
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }

        public void TrimCharacter() {
            var f1 = new FieldText("Characters", "Leading or trailing characters to remove", "");
            var f2 = new FieldCheckBox("Remove leading characters", "", true);
            var f3 = new FieldCheckBox("Remove trailing characters", "", true);
            new InputBox(_excelapp, "Trim characters", f1, f2, f3).Show(delegate {
                char[] chars = f1.Value.ToCharArray();
                bool trimLeft = f2.Value;
                bool trimRigth = f3.Value;
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string) {
                        if (trimLeft && trimRigth)
                            value = ((string)value).Trim(chars);
                        else if (trimLeft)
                            value = ((string)value).TrimStart(chars);
                        else if (trimRigth)
                            value = ((string)value).TrimEnd(chars);
                    }
                });
            });
        }

        public void Remove() {
            var f1 = new FieldText("Characters", "Characters to remove", "");
            new InputBox(_excelapp, "Remove", f1).Show(delegate {
                string str = f1.Value;
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string && ((string)value).Length != 0)
                        value = ((string)value).Replace(str, "");
                });
            });
        }

        public void Add() {
            var f1 = new FieldText("Characters", "Characters to add", "");
            var f2 = new FieldRadioBT("", new string[] { "Left", "Rigth" }, "Position", 0, true);
            new InputBox(_excelapp, "Add", f1, f2).Show(delegate {
                string str = f1.Value;
                bool left = f2.Value == 0;
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string) {
                        if (left)
                            value = str + (string)value;
                        else
                            value = (string)value + str;
                    }
                });
            });
        }

        public void Clean() {
            try {
                new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                    if (value is string) {
                        string txt = string.Empty;
                        foreach (char car in ((string)value).Replace('\t', ' '))
                            if (car >= ' ')
                                txt += car;
                        value = txt;
                    }
                });
            } catch (Exception ex) { new FrmException(_excelapp, ex).ShowDialog(); }
        }
        public void Truncate() {
            var f1 = new FieldNumber("Length", "Maximum length for the text", 256d, 0, 1000);
            var f2 = new FieldRadioBT("Position", new[] { "Left", "Rigth" }, "Position", 0);
            new InputBox(_excelapp, "Truncate", f1, f2).Show(delegate {
                int maxlen = (int)(f1.Value ?? 0);
                if (f2.Value == 0)
                    new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                        if (value is string)
                            if (((string)value).Length > maxlen)
                                value = ((string)value).Substring(0, maxlen);
                    });
                else
                    new CellsOperator(_range).ForEachValue(null, delegate(ref object value) {
                        if (value is string)
                            if (((string)value).Length > maxlen)
                                value = ((string)value).Substring(((string)value).Length - maxlen);
                    });
            });

        }

        public void Pad() {
            var f1 = new FieldText("Character", "Character to add", "0", "^.$", "One character only");
            var f2 = new FieldNumber("Length", "Total length", 10d, 1, 1000);
            var f3 = new FieldRadioBT("Insert position", new[] { "Left", "Rigth" }, "Insert position", 0);
            new InputBox(_excelapp, "Padding", f1, f2, f3).Show(delegate {
                char char_ = f1.Value[0];
                int len = (int)(f2.Value ?? 0);
                if (f3.Value == 0) {
                    new CellsOperator(_range).ForEachValue("@", delegate(ref object value) {
                        value = value.ToString().PadLeft(len, char_);
                    });
                } else if (f3.Value == 1) {
                    new CellsOperator(_range).ForEachValue("@", delegate(ref object value) {
                        value = value.ToString().PadRight(len, char_);
                    });
                }
            });
        }

        public void RegexReplace() {
            var f1 = new FieldText("Pattern", "Regular expression pattern to match.", @"^(.*)$", true);
            var f2 = new FieldText("Replacement", "Replacement string", @"\1", true);
            new InputBox(_excelapp, "Replace (Regex)", f1, f2).Show(delegate {
                string pattern = f1.Value;
                string replacement = System.Text.RegularExpressions.Regex.Replace(f2.Value, @"\\(\d)", @"$$1").Replace(@"\t", "\t");
                new CellsOperator(_range).ForEachValue("@", delegate(ref object value) {
                    value = System.Text.RegularExpressions.Regex.Replace(value.ToString(), pattern, replacement);
                });
            });
        }

        public void Split() {
            if (_range.Areas.Count != 1 || _range.Areas[1].Columns.Count != 1) {
                MsgBox.ShowError(_excelapp, "Select one column only.");
                return;
            }
            var f0 = new FieldRadioBT("Type", new string[] { "Separator", "Regex" }, null, 0, true);
            var f1 = new FieldText("Separator", "String separator", "", true);
            var f2 = new FieldText("Regex pattern", "Regex pattern", @"[^ ]+", true);
            f0.ValueChanged += (sender, e) => {
                f1.Control.Enabled = f0.Value == 0;
                f2.Control.Enabled = f0.Value == 1;
            };
            f2.Control.Enabled = false;
            new InputBox(_excelapp, "Replace (Regex)", f0, f1, f2).Show(delegate {
                bool useSeparator = f0.Value == 0;
                var range = (Excel.Range)_range.Areas[1].Columns[1];
                try {
                    _excelapp.ScreenUpdating = false;
                    Undo.AddUndoArea(range);
                    range.Copy();
                    var data = Clipboard.GetText();
                    _excelapp.CutCopyMode = 0;
                    var res = new StringBuilder();
                    if (useSeparator) {
                        var separator = f1.Value;
                        res.Append(data.Replace(separator, "\t"));
                    } else {
                        string pattern = f2.Value;
                        var rows = data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                        int nbRows = rows.Length;
                        for (int r = 0; r < nbRows; r++) {
                            var matches = Regex.Matches(rows[r], pattern);
                            int nbMatch = matches.Count;
                            for (int i = 0; i < nbMatch; i++) {
                                if (i != 0) res.Append('\t');
                                res.Append(matches[i].Value);
                            }
                            res.Append("\r\n");
                        }
                    }
                    Clipboard.SetText(res.ToString());
                    range.PasteSpecial();
                    Clipboard.Clear();
                    (_excelapp.ActiveWindow.RangeSelection).NumberFormat = "";
                } catch { throw; } finally {
                    _excelapp.ScreenUpdating = true;
                }
            });
        }

    }
}